package com.douqu.game.core.netty;

import com.douqu.game.core.database.model.IllegalityModel;
import com.douqu.game.core.database.model.PlayerModel;
import com.douqu.game.core.e.E_ConnectionDestroyType;
import com.douqu.game.core.e.E_IllegalityType;
import com.douqu.game.core.e.E_ServerType;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.factory.WordFactory;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.protobuf.SGMainProto;
import com.douqu.game.core.protobuf.SGSystemProto;
import com.douqu.game.core.util.LogUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;

import java.net.InetSocketAddress;
import java.nio.ByteOrder;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Administrator on 2017/3/15.
 */
public class  NettyConnection
{
    public final static int CHECK_TIME = 3000;

    public final static int CHECK_COUNT = 100;

    private int id;

    private String ip;

    private Channel channel;

    private E_ServerType serverType;

    private Object object;

    private int receiveMsgCount;

    private Map<Integer, Integer> msgMap = new ConcurrentHashMap<>();

    private int sendMsgCount;

    /**
     * 是否是服务器主动断开
     */
    private E_ConnectionDestroyType destroyType;

    private long createTime;


    /**
     * 上一次检测异常时间
     */
    private long preCheckTime;

    /**
     * GM账号更新配置文件的时间
     */
    private long lastUpdateConfigTime;

    private long lastUpdateTime;

    private List<PlayerModel> mergePlayers;

    public NettyConnection(Channel channel, long currentTime)
    {
        this.id = hashCode();
        this.channel = channel;

        if(channel != null)
        {
            InetSocketAddress address = ((InetSocketAddress) channel.remoteAddress());
            this.ip = address.getAddress().getHostAddress();
        }

        this.createTime = currentTime;
    }

    private void sendAlert(SGCommonProto.E_NOTIFY_TYPE notifyType, String content)
    {
        if(channel == null)
            return;

        SGSystemProto.S2C_NotifyAlert.Builder response = SGSystemProto.S2C_NotifyAlert.newBuilder();
        response.setType(notifyType);
        response.setContent(content==null?"":content);
        sendMsg(SGMainProto.E_MSG_ID.MsgID_System_NotifyAlert_VALUE, response.build().toByteArray());
    }

    /**
     * 防止前端收不到包一直转圈
     */
    public void sendUnknown()
    {
        sendAlert(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_UNKNOWN, null);
    }


    public void sendWarn(String key, Object... params)
    {
        sendAlert(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_WARN, WordFactory.getWord(key, params));
    }

    public void sendGM(String content)
    {
        sendAlert(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_GM, content);
    }

    public void sendGet(String content)
    {
        sendAlert(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_GET, content);
    }

    public void sendSystem(String content)
    {
        sendAlert(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_SYSTEM, content);
    }


    public void sendMsg(int msgID, byte[]... data)
    {
        byte[] sendData = data.length == 0 ? null : data[0];

        final ByteBuf byteBuf = Unpooled.buffer();//Unpooled.directBuffer();

        int length = sendData == null ? 0 : sendData.length;

        if(ByteOrder.nativeOrder().toString().equals(ByteOrder.LITTLE_ENDIAN.toString())){
            byteBuf.writeIntLE(length);//总包长
            byteBuf.writeShortLE(msgID);//长度为2
        }else{
            byteBuf.writeInt(length);//总包长
            byteBuf.writeShort(msgID);//长度为2
        }

        if(sendData != null)
            byteBuf.writeBytes(sendData);

        channel.writeAndFlush(byteBuf);

        sendMsgCount++;

        lastUpdateTime = DataFactory.currentTime;

//        ReferenceCountUtil.release(byteBuf);
    }


    public IllegalityModel receiveMsg(long currentTime, int code)
    {
        lastUpdateTime = currentTime;

        receiveMsgCount++;
        Integer value = msgMap.get(code);
        if(value == null)
        {
            msgMap.put(code, 1);
        }
        else
        {
            msgMap.put(code, value+1);
        }

        if(preCheckTime == 0)
            preCheckTime= currentTime;
        else
        {
            if(currentTime - preCheckTime >= CHECK_TIME)
            {
                if(receiveMsgCount >= CHECK_COUNT)
                {
                    IllegalityModel model = new IllegalityModel();
                    model.setIp(ip);
                    model.setType(E_IllegalityType.MSG_COUNT.getCode());
                    model.setContent(MessageFormat.format(E_IllegalityType.MSG_COUNT.getMsg(), CHECK_TIME/1000, CHECK_COUNT));
                    model.setStartTime(new Date(preCheckTime));
                    model.setEndTime(new Date(currentTime));
                    model.setCreateTime(new Date(currentTime));
                    model.setDetail(msgMap.toString());

                    receiveMsgCount = 0;
                    msgMap.clear();
                    preCheckTime = currentTime;

                    return model;
                }
            }
        }

        return null;
    }


    public void sendOffline()
    {
//        sendWarn(WordFactory.PLAYER_OVERDUE);

        LogUtils.warn("发送离线---------->");

        sendMsg(SGMainProto.E_MSG_ID.MsgID_System_Offline_VALUE, SGSystemProto.S2C_Offline.newBuilder().build().toByteArray());
    }

    public void destroy()
    {
        if(channel == null)
            return;

        channel.close();

        object = null;
    }

//    public String msgToString()
//    {
//        StringBuilder result = new StringBuilder();
//        for(Integer code : msgMap.keySet())
//        {
//
//        }
//    }

    public boolean isOverdue(final long currentTime)
    {
        return lastUpdateConfigTime > 0 && currentTime - lastUpdateConfigTime >= 240000 && object == null;
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getIp() {
        return ip;
    }

    public String getRemoteAddress()
    {
        return channel.remoteAddress().toString();
    }
    public Channel getChannel() {
        return channel;
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public E_ServerType getServerType() {
        return serverType;
    }

    public void setServerType(E_ServerType serverType) {
        this.serverType = serverType;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public int getReceiveMsgCount() {
        return receiveMsgCount;
    }

    public int getSendMsgCount() {
        return sendMsgCount;
    }


    public long getLastUpdateConfigTime() {
        return lastUpdateConfigTime;
    }

    public void setLastUpdateConfigTime(long lastUpdateConfigTime) {
        this.lastUpdateConfigTime = lastUpdateConfigTime;
    }

    public E_ConnectionDestroyType getDestroyType() {
        return destroyType;
    }

    public void setDestroyType(E_ConnectionDestroyType destroyType) {
        this.destroyType = destroyType;
    }

    public List<PlayerModel> getMergePlayers() {
        return mergePlayers;
    }

    public void setMergePlayers(List<PlayerModel> mergePlayers) {
        this.mergePlayers = mergePlayers;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof NettyConnection)) return false;

        NettyConnection that = (NettyConnection) o;

        if (id != that.id) return false;

        return true;
    }


    @Override
    public String toString() {
        return "{" +
                "id=" + id +
                ", channel=" + channel.remoteAddress() +
                ", serverType=" + serverType +
                ", destroyType=" + destroyType +
                ", object=" + object +
                '}';
    }
}
